﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Input;
using System.Collections.ObjectModel;
using Ppt = Microsoft.Office.Interop.PowerPoint;
using MVVM.Core;
using ObjectModel.PowerPoint;
using ObjectModel.PowerPoint.New;
using ViewComponents.Services;

namespace ViewComponents.PowerPoint.ViewModels
{
    public class ConstantsViewModel : ViewModelBase
    {
        #region Declarations

        readonly Ppt.Presentation mPres = Globals.Application.ActivePresentation;
        readonly IWindowService mWindowService;
        readonly IDialogService mDialogService;
        Constant mSelectedItem;

        #endregion

        #region Properties

        public ObservableCollection<Constant> Constants
        {
            get { return Globals.PresentationConstants[mPres].Constants; }
        }

        public Constant SelectedItem
        {
            get { return mSelectedItem; }
            set
            {
                if (mSelectedItem == value) return;
                mSelectedItem = value;
                OnPropertyChanged("SelectedItem");
            }
        }

        bool mIsCollectionFocused;
        public bool IsCollectionFocused
        {
            get { return mIsCollectionFocused; }
            set
            {
                if (mIsCollectionFocused == value) return;
                mIsCollectionFocused = value;
                OnPropertyChanged("IsCollectionFocused");
            }
        }

        bool mIsDefaultInitialFocus;
        public bool IsDefaultInitialFocus
        {
            get { return mIsDefaultInitialFocus; }
            set
            {
                if (mIsDefaultInitialFocus == value) return;
                mIsDefaultInitialFocus = value;
                OnPropertyChanged("IsDefaultInitialFocus");
            }
        }

        #endregion

        #region Constructors

        public ConstantsViewModel() :
            this(new BasicWindowService(), new MessageBoxDialogService()) { }

        public ConstantsViewModel(IWindowService windowService, IDialogService dialogService)
        {
            mWindowService = windowService;
            mDialogService = dialogService;

            SetInitialFocus();
        }

        #endregion

        #region Commands

        public ICommand AddCommand
        {
            get { return new ViewModelCommand(AddExecute); }
        }

        public ICommand EditCommand
        {
            get { return new ViewModelCommand(EditExecute, CanEditExecute, this); }
        }

        public ICommand RemoveCommand
        {
            get { return new ViewModelCommand(RemoveExecute, CanRemoveExecute, this); }
        }

        #endregion

        #region Command Methods

        void AddExecute()
        {
            // Create a temporary object and pass it to a dialog service.
            Constant constant = new Constant();
            if ((bool)mWindowService.ShowViewModelInDialog<EditConstantWindow>(constant))
                Add(constant);

            if (Constants.Count > 0)
                IsCollectionFocused = true;
        }

        bool CanEditExecute()
        {
            return SelectedItem == null ? false : true;
        }

        void EditExecute()
        {
            // Make a copy of the selected item and pass it to a dialog service.
            Constant constant = new Constant { Name = SelectedItem.Name, Value = SelectedItem.Value };
            if ((bool)mWindowService.ShowViewModelInDialog<EditConstantWindow>(constant))
                SetSelected(constant);

            IsCollectionFocused = true;
        }

        bool CanRemoveExecute()
        {
            return SelectedItem == null ? false : true;
        }

        void RemoveExecute()
        {
            string msg = string.Format("\"{0}\" may be referenced elsewhere in the presentation." +
                "\n\nAre you sure you want to remove this constant?", SelectedItem.Name);

            DialogResponse response = mDialogService.ShowMessage(msg, "Remove Constant",
                DialogButton.YesNo, DialogImage.Exclamation, DialogResponse.No);

            if (response == DialogResponse.Yes)
                RemoveSelected();
        }

        #endregion

        #region Methods

        void SetInitialFocus()
        {
            if (Constants.Count > 0)
            {
                SelectedItem = Constants.First();
                IsCollectionFocused = true;
            }
            else
                IsDefaultInitialFocus = true;
        }

        void Add(Constant constant)
        {
            if (string.IsNullOrEmpty(constant.Name))
                ThrowBlankNameException();
            // Check if there is already another constant in the collection
            // with the same name.
            else if (Constants.Any(c => c.Name == constant.Name))
                ThrowDuplicateNameException(constant.Name);
            else
            {
                Constants.Add(constant);
                SelectedItem = constant;
            }
        }

        void Remove(Constant constant)
        {
            Constants.Remove(constant);
            // REMOVE ALL SOURCE REFERENCES TO THIS CONSTANT.
            throw new NotImplementedException();
        }

        void RemoveSelected()
        {
            Remove(SelectedItem);
            SelectedItem = null;
        }

        void SetSelected(Constant constant)
        {
            if (string.IsNullOrEmpty(constant.Name))
            {
                ThrowBlankNameException();
                return;
            }

            // Check if there is already another constant in the collection
            // with the same name.
            IEnumerable<Constant> sel = new[] { SelectedItem };
            if (Constants.Except(sel).Any(c => c.Name == constant.Name))
                ThrowDuplicateNameException(constant.Name);
            else
            {
                SelectedItem.Name = constant.Name;
                SelectedItem.Value = constant.Value;
            }
        }


        void ThrowBlankNameException()
        {
            string msg = "Name cannot be blank. Please specify a name for this constant.";
            mDialogService.ShowException(msg);
        }

        void ThrowDuplicateNameException(string name)
        {
            string msg = string.Format("A constant with the name \"{0}\" already exists.", name);
            mDialogService.ShowException(msg);
        }

        #endregion
    }
}
